﻿using System;
using System.Drawing;
using System.Windows.Forms;
using HDM.NexusEngine.Core;
using HDM.NexusEngine.Input;

namespace HDM.NexusEngine.Shooter
{
    public class Level
    {
        private readonly InputManager _input;
        private PersistantGameData _gameData;
        private readonly ScrollingBackground _background;
        private readonly ScrollingBackground _backgroundLayer;
        private readonly BulletManager _bulletManager = new BulletManager(new RectangleF(-1300/2, -750/2, 1300, 750));
        private readonly EffectsManager _effectsManager;
        private readonly EnemyManager _enemyManager;

        public PlayerCharacter Player { get; private set; }
        
        public Level(InputManager input, TextureManager textureManager, PersistantGameData gameData)
        {
            _input = input;
            _gameData = gameData;
            var textureManager1 = textureManager;
            _effectsManager = new EffectsManager(textureManager1);
            Player = new PlayerCharacter(textureManager1, _bulletManager);

            // -1300 is bad for two reasons
            // 1. It's a magic number in the middle of the code
            // 2. It's based on the size of the form but doesn't directly reference the size of the form
            // this means duplication and two places to edit the code if the form size changes.
            // The form size and the enemy manager play area size should both get their value
            // from one central place.
            _enemyManager = new EnemyManager(textureManager1, _effectsManager, _bulletManager, Player, -1300);

            _background = new ScrollingBackground(textureManager.Get("background"));
            _background.SetScale(2, 2);
            _background.Speed = 0.15f;

            _backgroundLayer = new ScrollingBackground(textureManager.Get("background_layer_1"));
            _backgroundLayer.SetScale(2.0, 2.0);
            _backgroundLayer.Speed = 0.1f;
        }

        public void Update(double elapsedTime, double gameTime)
        {
            UpdateCollisions();
            _bulletManager.Update(elapsedTime);
            _bulletManager.UpdatePlayerCollision(Player);
            _background.Update((float)elapsedTime);
            _backgroundLayer.Update((float)elapsedTime);
            _effectsManager.Update(elapsedTime);
            _enemyManager.Update(elapsedTime, gameTime);
            Player.Update(elapsedTime);

            UpdateInput(elapsedTime);
        }

        public void Render(Renderer renderer)
        {
            _background.Render(renderer);
            _backgroundLayer.Render(renderer);
            Player.Render(renderer);
            _bulletManager.Render(renderer);
            _effectsManager.Render(renderer);
            _enemyManager.Render(renderer);
        }

        private void UpdateInput(double elapsedTime)
        {
            var controlInput = new Vector(0, 0, 0);

            if (_input.Controller != null)
            {
                // Get controls and apply to player character.
                double x = _input.Controller.LeftControlStick.X;
                double y = _input.Controller.LeftControlStick.Y * -1;
                controlInput = new Vector(x, y, 0);

                if (_input.Controller.ButtonA.Pressed)
                    Player.Fire();
            }

            if (_input.Keyboard.IsKeyPressed(Keys.Space))
                Player.Fire();

            if (Math.Abs(controlInput.Length()) < 0.0001)
            {
                // If the input is very small, then the player may not be using a controller;
                // they may be using the keyboard.
                if (_input.Keyboard.IsKeyHeld(Keys.Left))
                {
                    controlInput.X = -1;
                }

                if (_input.Keyboard.IsKeyHeld(Keys.Right))
                {
                    controlInput.X = 1;
                }

                if (_input.Keyboard.IsKeyHeld(Keys.Up))
                {
                    controlInput.Y = 1;
                }

                if (_input.Keyboard.IsKeyHeld(Keys.Down))
                {
                    controlInput.Y = -1;
                }
            }

            Player.Move(controlInput * elapsedTime);
        }

        private void UpdateCollisions()
        {
            foreach (var enemy in _enemyManager.EnemyList)
            {
                if (enemy.GetBoundingBox().IntersectsWith(Player.GetBoundingBox()))
                {
                    enemy.OnCollision(Player);
                    Player.OnCollision(enemy);
                }

                _bulletManager.UpdateEnemyCollisions(enemy);
            }
        }
    }
}